package com.phei.netty.chat4;

import java.io.RandomAccessFile;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.DefaultFileRegion;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.stream.ChunkedNioFile;

public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest>{
    //扩展SimpleChannelInboundHandler用于处理FullHttpRequest信息
    private final String wsuri;
//    private static final File index;
//    
//    static {
//        URL location = HttpRequestHandler.class
//                .getProtectionDomain().getCodeSource().getLocation();
//        try {
//            String path = location.toURI() + "html/index.html";
//            path = !path.contains("file:") ? path : path.substring(5);
//            index = new File(path);
//        } catch (Exception e) {
//            e.printStackTrace();
//            throw new IllegalStateException("can't find index.html");
//        }
//    }
    
    public HttpRequestHandler(String wsuri){
        this.wsuri = wsuri;
    }
    
    @Override
    
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request)
    		throws Exception {
        if(wsuri.equalsIgnoreCase(request.uri())){
            //如果请求的是WebSocket升级，将其传递给在ChannelPipeline中的下一个ChannelInboundHandler处理
            //这里跟第一个例子的websocket协议升级判断方式是不同的 因为只只是判断uri路径而已
            //对应的js请求路径 socket = new WebSocket("ws://localhost:8080/ws");
            ctx.fireChannelRead(request.retain());
        }else{
            //处理100continue
            if(HttpUtil.is100ContinueExpected(request)){
                send100Continue(ctx);
            }
            //读取默认页
            RandomAccessFile file = new RandomAccessFile("C:\\html\\index.html", "r");
            
            HttpResponse response = new DefaultHttpResponse(
                    request.protocolVersion(), HttpResponseStatus.OK);
            response.headers().set(HttpHeaderNames.CONTENT_TYPE, 
                    "text/html; charset=UTF-8");
            
            boolean keepAlive = HttpUtil.isKeepAlive(request);
            if(keepAlive){
                response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, (int) file.length());
                response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
            }
            ctx.write(response);
            
            if(ctx.pipeline().get(SslHandler.class) == null){
                //如果不是https安全连接的话 要达到最大效率的话，可以通过把index.html直接存储在DefaultFileRegion中
                //实现零拷贝传输 就是不拷贝到内存，直接读取文件通过文件输出流进行处理
                ctx.write(new DefaultFileRegion(file.getChannel(), 0, file.length()));
            }else{
                //否则要读取全部文件，然后处理加密，在发送，只不过这一切都有netty内部处理
                //A ChunkedInput that fetches data from a file chunk by chunk using NIO FileChannel.
                //If your operating system supports zero-copy file transfer such as sendfile(), 
                //you might want to use FileRegion instead.
                ctx.write(new ChunkedNioFile(file.getChannel()));
            }
            ChannelFuture future = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
            
            if(!keepAlive){
                future.addListener(ChannelFutureListener.CLOSE);
            }
            file.close();
        }
    }

    private static void send100Continue(ChannelHandlerContext ctx){
        FullHttpResponse response = (FullHttpResponse) new DefaultHttpResponse(
                HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE);
        ctx.writeAndFlush(response);
    }
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        Channel incoming = ctx.channel();
        System.out.println("Client:"+incoming.remoteAddress()+"exception.");
        cause.printStackTrace();
        ctx.close();
    }
}